package com.insight.modules.system.util;

import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.jeecgframework.poi.excel.ExcelExportUtil;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ExportParams;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.jeecgframework.poi.excel.entity.enmus.ExcelType;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

/**
 * Excel 工具类，支持导入、导出、文件格式判断、错误信息收集与下载功能。
 * 兼容 Excel 2003（.xls）和 Excel 2007 及以上（.xlsx）格式。
 * 使用 Apache POI 和 easyexcel 封装库。
 */
public class ExcelUtil {

    /**
     * 判断是否为 Excel 2003 格式（.xls）。
     *
     * @param filePath 文件路径
     * @return true 表示为 Excel 2003 格式
     */
    public static boolean isExcel2003(String filePath) {
        return filePath.matches("^.+\\.(?i)(xls)$");
    }

    /**
     * 判断是否为 Excel 2007 或更高格式（.xlsx）。
     *
     * @param filePath 文件路径
     * @return true 表示为 Excel 2007+ 格式
     */
    public static boolean isExcel2007(String filePath) {
        return filePath.matches("^.+\\.(?i)(xlsx)$");
    }

    /**
     * 获取 Workbook 对象，自动适配 .xls 和 .xlsx。
     *
     * @param file 上传的 Excel 文件
     * @return Workbook 对象
     * @throws IOException 文件读取异常
     */
    public static Workbook getWorkBook(MultipartFile file) throws IOException {
        if (file == null) {
            throw new IOException("文件为空");
        }
        InputStream is = file.getInputStream();
        if (is == null) {
            throw new IOException("无法获取文件输入流");
        }
        Workbook workbook;
        try {
            workbook = new HSSFWorkbook(is);// 尝试解析为 xls
        } catch (Exception ex) {
            is = file.getInputStream();// 重新获取流
            if (is == null) {
                throw new IOException("无法重新获取文件输入流");
            }
            workbook = new XSSFWorkbook(is);// 尝试解析为 xlsx
        }
        return workbook;
    }

    /**
     * 构建错误提示信息（用于 Excel 导入校验）。
     *
     * @param sb   错误信息 StringBuilder
     * @param list 当前对象列表
     * @param i    当前处理的索引
     * @param obj  当前对象
     * @param name 错误属性字段名
     * @param msg  错误提示前缀
     */
    public static void getWrongInfo(StringBuilder sb, List<?> list, int i, Object obj, String name, String msg) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        Class<?> clazz = obj.getClass();
        Object value = null;
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            if (f.getName().equals(name)) {
                PropertyDescriptor pd = new PropertyDescriptor(f.getName(), clazz);
                Method getMethod = pd.getReadMethod();
                value = getMethod.invoke(obj);
                break;
            }
        }
        if (i == 0) {
            sb.append(msg).append(value).append(';');
        } else if (i == list.size() - 1) {
            sb.append(value).append("</br>");
        } else {
            sb.append(value).append(';');
        }
    }

    // ========== 导出功能 ==========

    /**
     * 导出 Excel（包含是否生成表头选项）。
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,
                                   String fileName, boolean isCreateHeader, HttpServletResponse response) {
        ExportParams exportParams = new ExportParams(title, sheetName);
        exportParams.setCreateHeadRows(isCreateHeader);
        defaultExport(list, pojoClass, fileName, response, exportParams);
    }

    /**
     * 导出 Excel（默认包含表头）。
     */
    public static void exportExcel(List<?> list, String title, String sheetName, Class<?> pojoClass,
                                   String fileName, HttpServletResponse response) {
        defaultExport(list, pojoClass, fileName, response, new ExportParams(title, sheetName));
    }

    /**
     * 导出动态 Map 格式的 Excel。
     */
    public static void exportExcel(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        defaultExport(list, fileName, response);
    }

    /**
     * 核心导出方法。
     */
    private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName,
                                      HttpServletResponse response, ExportParams exportParams) {
        Workbook workbook = ExcelExportUtil.exportExcel(exportParams, pojoClass, list);
        downLoadExcel(fileName, response, workbook);
    }

    /**
     * 下载 Excel 文件。
     */
    public static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) {
        try {
            response.setHeader("content-Type", "application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
            response.setCharacterEncoding("UTF-8");
            workbook.write(response.getOutputStream());
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                workbook.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Map 数据导出处理。
     */
    private static void defaultExport(List<Map<String, Object>> list, String fileName, HttpServletResponse response) {
        Workbook workbook = ExcelExportUtil.exportExcel(list, ExcelType.HSSF);
        if (workbook != null) {
            downLoadExcel(fileName, response, workbook);
        }
    }

    // ========== 导入功能 ==========

    /**
     * 从 Excel 文件路径导入数据。
     */
    public static <T> List<T> importExcel(String filePath,Integer titleRows,Integer headerRows, Class<T> pojoClass){
        if (StringUtils.isBlank(filePath)){
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        List<T> list = null;
        try {
            list = ExcelImportUtil.importExcel(new File(filePath), pojoClass, params);
        }catch (NoSuchElementException e){
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 从 MultipartFile 导入数据。
     */
    public static <T> List<T> importExcel(MultipartFile file, Integer titleRows, Integer headerRows, Class<T> pojoClass) {
        if (file == null || pojoClass == null || titleRows == null || headerRows == null) {
            return null;
        }
        ImportParams params = new ImportParams();
        params.setTitleRows(titleRows);
        params.setHeadRows(headerRows);
        try {
            return ExcelImportUtil.importExcel(file.getInputStream(), pojoClass, params);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    // ========== 下载辅助 ==========

    /**
     * 下载 xlsx 文件（POI方式）。
     */
    public static void downloadPoi(InputStream inputStream, HttpServletResponse response, String name) throws IOException {
        try (XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
             ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/binary;charset=ISO8859-1");
            response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(name, "UTF-8"));
            workbook.write(out);
            out.flush();
        }
    }

    /**
     * 下载 xls 文件（POI方式）。
     */
    public static void downloadPoiLedgerMoth(InputStream inputStream, HttpServletResponse response, String name) throws IOException {
        try (HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
             ServletOutputStream out = response.getOutputStream()) {
            response.setContentType("application/binary;charset=ISO8859-1");
            response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(name, "UTF-8"));
            workbook.write(out);
            out.flush();
        }
    }

    /**
     * 通过 File 对象下载文件。
     *
     * @param file     目标文件
     * @param response 响应对象
     * @param name     下载文件名（不带扩展名）
     */
    public static void download(File file, HttpServletResponse response, String name) throws IOException {
        if (file == null || !file.exists() || !file.isFile()) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "文件不存在");
            return;
        }

        String originalName = file.getName();
        String extension = originalName.substring(originalName.lastIndexOf('.'));
        String downloadName = name + extension;

        response.reset();
        response.setContentType("application/force-download");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(downloadName, "UTF-8"));
        response.setCharacterEncoding("UTF-8");

        try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(file.toPath()));
             BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream())) {

            byte[] buffer = new byte[4096];
            int bytesRead;
            while ((bytesRead = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, bytesRead);
            }
            bos.flush();
        }
    }
}

